import sys
from typing import Sequence, Dict, MutableSequence
import pytest
import json
import os
import shutil


class ReportHelper:
    __data: dict
    """
    约定大于配置
    {
  "allure_result_path": "allure-result",
  "allure_report_path": "allure-report",
  "allure_history_source_path": "allure-report/history",
  "allure_history_target_path": "allure-result/history",
  "allure_link_pattern": 
}
    """
    @property
    def allure_result_path(self) -> str:
        return "allure-result"

    @property
    def allure_report_path(self) -> str:
        return "allure-report"

    @property
    def allure_history_source_path(self) -> str:
        report_path = self.allure_report_path
        if not report_path:
            return ""
        return f"{report_path}/history"

    @property
    def allure_history_target_path(self) -> str:
        result_path = self.allure_result_path
        if not result_path:
            return ""
        return f"{result_path}/history"

    @property
    def allure_host(self) -> str:
        return "127.0.0.1"

    @property
    def allure_port(self) -> str:
        return "8081"

    @property
    def allure_link_pattern(self) -> Sequence[str]:
        return ["issue:https://github.com/allure-framework/allure-python/issues/{}"]

    @property
    def allure_summary_path(self) -> str:
        result_path = self.allure_result_path
        if not result_path:
            return ""
        return f"{result_path}/widgets/summary.json"

    @staticmethod
    def run_command(c: str):
        error_gene = os.popen(c)
        # 读下内容，防止阻塞异步执行
        error_content = error_gene.read()
        exit_code = error_gene.close()
        if exit_code:
            raise Exception(error_content)

    def make_property_file(self, source: str):
        """
        加载source指定的environment.properties文件，并将kwargs指定的内容更新进去。将结果文件写到allure_result_path中去

        :param source: source的文件可以不存在。
        :param kwargs:
        :return:
        """

        # 支持下environment.properties不存在清空
        if os.path.exists(source):
            result_path_property = os.path.join(self.allure_result_path, "environment.properties")
            shutil.copy(source, result_path_property)

    def make_category(self, source: str):
        """
        如果源文件存在就把文件复制到allure_result_path,并改名为categories.json
        :param source:
        :return:
        """
        if os.path.exists(source):
            result_path_category = os.path.join(self.allure_result_path, "categories.json")
            shutil.copy(source, result_path_category)

    def make_history(self):
        """
        将allure_history_source_path中history目录拷贝allure_history_target_path。如果之前存在allure_history_target_path，先删除
        :return:
        """
        # 清空report目录前先拷贝
        if os.path.exists(self.allure_history_source_path):
            # 做下兜底，如果没有指定--clean-alluredir,allure_history_target_path就会存在
            if os.path.exists(self.allure_history_target_path):
                shutil.rmtree(self.allure_history_target_path)
            shutil.copytree(self.allure_history_source_path, self.allure_history_target_path)

    def generate_report(self):
        """
        确保你的allure在path中。将报告生成到allure_report_path
        :param source:
        :param kwargs:
        :return:
        """

        # 这里一定要加-c清理之前生成的report
        command_gene = f"allure generate -c -o {self.allure_report_path} {self.allure_result_path}"
        self.run_command(command_gene)

    def open_report(self):
        """
        确保你的allure在path中
        :param source:
        :param kwargs:
        :return:
        """
        command_open = f"allure open --host {self.allure_host} --port {self.allure_port} {self.allure_report_path}"
        self.run_command(command_open)

    def report_summary(self) -> Dict[str, str]:
        """
        total  总用例
        passed   通过
        failed  失败
        skipped    跳过
        run_time 时间
        min_time  最小单用例运行时间
        max_time  最大单用例运行时间
        :return:
        """
        with open(self.allure_summary_path, 'rt', encoding="utf-8") as f:
            data = json.loads(f.read())
        return dict(
            total=data['statistic']['total'],  # 总用例
            passed=data['statistic']['passed'],  # 通过
            failed=data['statistic']['failed'],  # 失败
            skipped=data['statistic']['skipped'],  # 跳过
            run_time=data['time']['duration'],  # 时间
            min_time=data['time']['minDuration'],  # 最小单用例运行时间
            max_time=data['time']['maxDuration']  # 最大单用例运行时间
        )





def send_ding_notification(config: dict, summary, address):
    """发送钉钉通知
        :param config: 添加配置项
        """
    # ding_conf = config["dingding"]
    # # 小钉，负责给钉钉群发送通知信息
    # xd = DingtalkChatbot(ding_conf["web_hook"], secret=ding_conf["secret"])
    #
    # # 发送钉钉通知mark_down 格式信息
    # msg = f"#### {config['project']}  \n\n>环境: TEST\n\n>" \
    #       f"执行人: {config['contract']}\n\n>总用例数: {summary['total']} " \
    #       f"\n\n>成功用例数: {summary['passed']}" \
    #       f" \n\n>失败用例数: {summary['failed']} \n\n>跳过用例数: {summary['skipped']}" \
    #       f" > ###### 测试报告 [详情]({address}) \n"
    #
    # xd.send_markdown(title=config.REPORT_TITLE, text=msg)
    pass


def dev_with_browser(base_opt: Sequence[str]):

    report_helper = ReportHelper()

    # 准备运行参数
    opts = ["--alluredir", report_helper.allure_result_path]
    for lp in report_helper.allure_link_pattern:
        opts.extend(["--allure-link-pattern", lp])
    opts.extend(base_opt) #传入的参数会带fod所以要放后面
    pytest.main(opts)

    # 处理environment.properties
    report_helper.make_property_file("environment.properties")
    # 处理categories.json
    report_helper.make_category("categories.json")

    # 处理history
    report_helper.make_history()

    # 执行生成清空report目录
    report_helper.generate_report()
    #report_helper.open_report()

    # 发送钉钉消息或者邮件
    #send_ding_notification(config, report_helper.report_summary(),f"{report_helper.allure_host}:{report_helper.allure_port}")


if __name__ == "__main__":
    dev_with_browser(sys.argv[1:])
